using GameFramework.Battle.Core;
using Gameplay.PVE.Config;
using Gameplay.PVE.Data;
using Gameplay.PVE.Utils;
using ImageEffects;
using NpcFramework;
using System.Collections;
using System.Collections.Generic;
using OWL.Rendering.HRP;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using Yoozoo.Framework.Managers;
using Yoozoo.Gta.Common;
using Yoozoo.HRP.Runtime;

namespace Gameplay.PVE
{
    public class PveMap
    {
        public enum EMapDirection
        {
            none,
            left,
            top,
            right,
            bottom,
        }

        private class MapData
        {
            public Dictionary<EMapDirection,bool> directionInfo = new Dictionary<EMapDirection, bool>
            {
                [EMapDirection.bottom] = false,
                [EMapDirection.top] = false,
                [EMapDirection.right] = false,
                [EMapDirection.left] = false,
            };
            public int mapId;
            public int index;
            public PveMapController.MapObjData objData;
            public PveMapData mapData;

            public MapData(int mapId,List<EMapDirection> dirList,float angle = 0)
            {
                this.mapId = mapId;
                for (int i = 0; i < dirList.Count; i++)
                {
                    directionInfo[dirList[i]] = true;
                }

            }

            public bool CheckIsValid(EMapDirection require,EMapDirection requireOut = EMapDirection.none, EMapDirection notOnly = EMapDirection.none)
            {
                bool isNotOnly = true;
                if (notOnly != EMapDirection.none)
                {
                    isNotOnly = false;
                    foreach (var item in directionInfo)
                    {
                        if (item.Value && notOnly != item.Key && require != item.Key)
                        {
                            isNotOnly = true;
                        }
                    }
                }
                bool isRequireOut = requireOut == EMapDirection.none || directionInfo[requireOut];
                bool isRequire = directionInfo[require];
                return isRequire && isRequireOut && isNotOnly;
            }
        }

        private struct MapObj
        {
            //表示在mapDataList中的序号
            public int index;
            public GameObject map;
            public GameObject building;
            public EMapDirection from;
            public Vector3 offset;
        }

        private Dictionary<int,MapData> mapList = new Dictionary<int,MapData>();
        private MapObj currentMapData;
        private MapObj nextMapData;
        private Dictionary<int,MapObj> aroundMapData = new Dictionary<int,MapObj>();
        private MapObj lastMapData;
        private GameObject root;
        private Vector3 currentPosition = new Vector3(0,0,0);
        private Vector3 currentMapPosition = new Vector3(0,0,0);
        private Vector3 nextMapPosition = new Vector3(100,0,100);
        public Vector3 enemySpawnPosition;
        private Vector3 currentOffset;
        private Vector3 nextPosition;
        private Vector3 nextOffset;
        private int currentEnemyIndex;
        private int currentMyIndex;
        private int currentMortalIndex;
        private int currentCarIndex;

        private int carCountMax;

        private List<Vector3> enemyBirthPositions = new List<Vector3>();
        private Vector3 myBirthPosition;
        private Vector3 myGotoPosition;
        private List<Vector3> mortalBirthPositions = new List<Vector3>();
        private Dictionary<int,PveRoadPath> roads = new Dictionary<int, PveRoadPath>();
        private List<List<Vector3>> carRoads = new List<List<Vector3>>();

        private EMapDirection requiredOut = EMapDirection.right;

        private EMapDirection rpgCenterDir = EMapDirection.none;

        public Vector3 rpgPosition;
        private RpgLevelData levelData;
        
        private Vector3 rpgCenterPosition = new Vector3(100 + 35.7f,0,100 - 16.8f);

        public class EnemySpawn
        {
            public Vector3 position;
            public int type;
            public float param;
            public int id;
            public int level;
            public int stageId;
            public int positionId;
            public float hatredDistance;
            public bool hasSpawned;
            public int unitType;//0 人   // 1 车
            public RpgSpecialObjectConfig specialObjectConfig;//特殊物件配表
            public bool hasParent;
            public List<int> childList;//孩子节点
            public int team;
            public int skillPriority;
            public int skillCd;
            public int skillBornCd;
        }

        public class ObstacleSpawn
        {
            public RpgLevelData.RpgObstacle obstacleInfo;
            public bool hasSpawned;
        }

        public class StageSpawn
        {
            public int id;
            public int stageType;
            public float stageParam;
            public int previousStage;
            public Vector3 startPosition;
            public bool hasSpawned;
            public float spawnTime;
        }

        public Dictionary<int, List<EnemySpawn>> enemys = new Dictionary<int, List<EnemySpawn>>();

        private Dictionary<int,Vector3> playerBirthPositions = new Dictionary<int,Vector3>();

        public Dictionary<int, List<ObstacleSpawn>> obstacles =
            new Dictionary<int, List<ObstacleSpawn>>();

        public List<StageSpawn> stages = new List<StageSpawn>();

        //地图方向相对于地图中心点的方向
        public static Vector3 GetDirection(EMapDirection direction)
        {
            if (direction == EMapDirection.left)
            {
                return new Vector3(-1f,0,0);
            }
            else if (direction == EMapDirection.right)
            {
                return new Vector3(1f,0,0);
            }
            else if (direction == EMapDirection.top)
            {
                return new Vector3(0,0,1f);
            }
            else if (direction == EMapDirection.bottom)
            {
                return new Vector3(0,0,-1);
            }

            return new Vector3(1f,0,0);
        }

        public void Hide()
        {
            PveSceneResourceManager.sceneSeparateMgr.SetLoadObjectActive(false);
            root.SetActive(false);
            foreach (var item in roadInfoQueue)
            {
                if (item.path != null)
                {
                    item.path.SetActive(false);
                }
            }
        }

        public void Show()
        {
            root.SetActive(true);
            PveSceneResourceManager.sceneSeparateMgr.SetLoadObjectActive(true);
            foreach (var item in roadInfoQueue)
            {
                if (item.path != null)
                {
                    item.path.SetActive(true);
                }
            }
        }

        private bool showRpgMap = false;
        
        public void ShowRpgMap(Vector3 position)
        {
            if (showRpgMap)
            {
                return;
            }
            //while (mapIndexQueue.Count > 0)
            //{
            //    var q = mapIndexQueue.Dequeue();
            //    GameObject.Destroy(q.prefabA);
            //    GameObject.Destroy(q.prefabB);
            //}
           
            CreateMapSegment(position,0);
            ApplyLightMap();
            showRpgMap = true;
        }

        public void HideRpgMap()
        {
            foreach (var item in stageMapDic.Values)
            {
                GameObject.Destroy(item);
            }
            stageMapDic.Clear();
            InitMapQueue();
            ApplyLightMap();
            showRpgMap = false;
        }
        
        public Vector3 GetStageStartPosition(int id)
        {
            Vector3 originDir = GetDirection(EMapDirection.top);
            Vector3 originPosition = new Vector3(PveUtils.globalRatio * id * 2, 0, 0) + originDir * 8;
            Vector3 currentDir = GetDirection(currentMapData.from);
            float angle = PveUtils.GetAngle(originDir, currentDir);
            Vector3 currentPosition = Quaternion.AngleAxis(angle, Vector3.up) * originPosition;
            return this.currentPosition + currentPosition;
        }

        public Vector3 GetStageEndPosition(int id)
        {

            Vector3 originDir = GetDirection(EMapDirection.top);
            Vector3 originPosition = new Vector3(-PveUtils.globalRatio * id * 2, 0, 0) + originDir * 8;
            Vector3 currentDir = GetDirection(GetOppositeDir(nextMapData.from));
            float angle = PveUtils.GetAngle(originDir, currentDir);
            Vector3 currentPosition = Quaternion.AngleAxis(angle, Vector3.up) * originPosition;
            return this.currentPosition + currentPosition;
        }


        public int GetCarCountMax()
        {
            return carCountMax;
        }
        

        public List<Vector3> GetMyRoadPathToRpg(int id)
        {
            var list = new List<Vector3>();
            for (int i = 0; i < currentRpgRegion.pathList.Count; i++)
            {
                list.Add(currentRpgRegion.pathList[i] + currentPosition);
            }

            return list;// List<Vector3>{GetSelfBirthPosition(id),GetSelfGotoPosition(id)};
        }
        
        public List<Vector3> GetEnemyRoadPath(Vector3 position)
        {
            int index = GetGraphIndex(2);
            if (roads.TryGetValue(index, out var road))
            {
                return road.GetRandomPathByStartPoint(position,currentPosition);
            }

            return new List<Vector3>();
        }

        public List<Vector3> GetMortalRoadPath(Vector3 position,bool isNext = false)
        {
            Vector3 originPosition = currentPosition;
            if (isNext)
            {
                originPosition = nextPosition;
            }
            int index = GetGraphIndex(1);
            if (roads.TryGetValue(index, out var road))
            {
                return road.GetRandomPathByStartPoint(position,originPosition);
            }

            return new List<Vector3>();
        }

        public Vector3 GetStageCenterPosition()
        {
            return currentPosition;
        }

        public Vector3 GetRpgStageCenterPosition()
        {
            //return currentRpgRegion.battlePosition + currentPosition;
            return rpgCenterPosition;
            //return new Vector3(6.9f, 0,-17.2f);
        }

        public Vector3 GetStageCenterPosition(int id)
        {
            Vector3 originDir = GetDirection(EMapDirection.top);
            Vector3 originPosition = new Vector3(PveUtils.globalRatio * id * 2, 0, 0);
            Vector3 currentDir = GetDirection(currentMapData.from);
            float angle = PveUtils.GetAngle(originDir, currentDir);
            Vector3 currentPosition = Quaternion.AngleAxis(angle, Vector3.up) * originPosition;
            return this.currentPosition + currentPosition;
        }

        public Vector3 GetStagePosition()
        {
            if (PveManager.Instance.isInPve)
            {
                return currentPosition;
            }
            return rpgPosition;
        }
        

        public Vector3 GetSelfBirthPositionRPG(int index)
        {
            return currentPosition + pveData.regions[0].position + PveUtils.GetSelfRpgPosition(index);
        }

        public Vector3 GetEnemyBirthPositionRPG(int index)
        {
            return currentPosition + PveUtils.GetEnemyRpgPosition(index);
        }

        public Vector3 GetSelfBirthPosition(int id)
        {
            if (PveManager.Instance.isToRpgTransition)
            {
                return currentBattleRegion.position + currentPosition + GetSelfOffset(id);
            }
            return currentPosition + GetSelfOffset(id);
        }

        private Vector3 GetSelfOffset(int id)
        {
            Vector3 offset = PveUtils.GetSelfPvePosOffset(id);
            Vector3 originDir = GetDirection(EMapDirection.top);
            Vector3 currentDir = GetDirection(currentMapData.from);
            float angle = PveUtils.GetAngle(originDir, currentDir);
            return Quaternion.AngleAxis(angle, Vector3.up) * offset;
        }

        private Vector3 GetEnemyOffset(int id)
        {
            Vector3 offset = PveUtils.GetEnemyPvePosOffset(id);
            Vector3 originDir = GetDirection(EMapDirection.top);
            Vector3 currentDir = GetDirection(GetOppositeDir(currentMapData.from));
            float angle = PveUtils.GetAngle(originDir, currentDir);
            return Quaternion.AngleAxis(angle, Vector3.up) * offset;
        }

        public Vector3 GetEnemyBirthPosition(int id,bool isNext = false)
        {
            /*var originPosition = enemySpawnPosition;

            var position = originPosition + GetEnemyOffset(id) + PveUtils.GetRandomVector3(new Vector3(-1f,0,-1f),new Vector3(-1f,0,-1f));*/
            if (pveEnemySpawns.Count <= id)
            {
                return currentPosition;
            }
            var position = pveEnemySpawns[id].position;
            return position;
        }

        public Vector3 GetNpcBirthPosition(int id, bool isNext = false)
        {
            var originPosition = currentPosition;
            if (isNext)
            {
                originPosition = nextPosition;
            }

            //if (id == 0)
            {
                return originPosition - new Vector3(100-83.5f,0,100 - 91.39f);
            }

            return originPosition + Vector3.zero;
        }

        public List<Vector3> GetCarRoad(bool isNext = false)
        {
            var list = new List<Vector3>();
            if (carRoads.Count == 0)
            {
                return list;
            }

            var originPosition = currentPosition;
            if (isNext)
            {
                originPosition = nextPosition;
            }

            for (int i = 0; i < carRoads[currentCarIndex].Count; i++)
            {
                list.Add(carRoads[currentCarIndex][i] + originPosition);
            }
            currentCarIndex++;
            if (currentCarIndex >= carRoads.Count)
            {
                currentCarIndex = 0;
            }
            return list;

        }

        public Vector3 GetMortalBirthPosition(bool isNext = false)
        {
            var originPosition = currentPosition;
            if (isNext)
            {
                originPosition = nextPosition;
            }
            if (mortalBirthPositions.Count == 0)
            {
                return originPosition;
            }
            var position =  originPosition + mortalBirthPositions[currentMortalIndex];
            currentMortalIndex++;
            if (currentMortalIndex >= mortalBirthPositions.Count)
            {
                currentMortalIndex = 0;
            }
            return position;
        }

        public void Init(Vector3 position)
        {
            currentPosition = position;
            root = new GameObject("[MapRoot]");
            root.transform.SetParent(PveScene.pveRootTrans);
            mapResourceId = isInLargeMap ? 30000001 : 30000000;
            CreateModelLight(false);
        }

        public void InitRpgData()
        {
            int levelId = 101;//PveUtils.GetRpgLevelId(PveManager.Instance.rpgLevelPassCount);
            levelData = PveResourceManager.Instance.GetRpgLevelDat(levelId);
            enemys.Clear();
            obstacles.Clear();
            stages.Clear();
            playerBirthPositions = PveUtils.GetRpgPlayerBirthPositions();
            if (PveGlobalVlues.LevelId != 0)
            {
                PveManager.Instance.RpgLevelId = PveGlobalVlues.LevelId;
            }
            var levelConfig = PveUtils.GetRpgLevelMonsterConfig(PveManager.Instance.RpgLevelId);
            if (levelConfig != null)
            {
                if (levelConfig.level_id_count.Count > levelConfig.monster_time.Count ||
                    levelConfig.level_id_count.Count > levelConfig.monster_place.Count)
                {
                    Debug.Log("配置错误");
                    return;
                }
                var enemys = new List<EnemySpawn>();
                Dictionary<int, List<int>> parentDic = new Dictionary<int, List<int>>();
                for (int i = 0; i < levelConfig.level_id_count.Count; i++)
                {
                    int id = levelConfig.level_id_count[i];
                    float time = levelConfig.GetValueFromArray(levelConfig.monster_time,i);
                    int level = levelConfig.GetValueFromArray(levelConfig.monster_level,i);
                    if (PveUtils.monsterLevels.Count > i)
                    {
                        level = PveUtils.monsterLevels[i];
                    }
                    
                    int placeIndex = levelConfig.GetValueFromArray(levelConfig.monster_place,i);
                    Vector3 position = Vector3.zero;
                    int team = 2;//默认为敌方
                    if (placeIndex == -1)//增援我方
                    {
                        team = 0;
                    }
                    
                    List<int> childList = new List<int>();
                    var specialObjectConfig = PveUtils.GetRpgSpecialObjectConfig(id);

                    if (specialObjectConfig == null && placeIndex != -1)
                    {
                        var placeConfig = PveUtils.GetRpgModelPlaceConfig(levelConfig.model_id, placeIndex);
                        if (placeConfig != null)
                        {
                            position = placeConfig.place_pos;
                        }
                    }
                    
                    
                    int parentIndex =  levelConfig.GetValueFromArray(levelConfig.parent,i);
                    if (parentIndex != 0)
                    {
                        List<int> children;
                        if (!parentDic.TryGetValue(parentIndex - 1, out children))
                        {
                            children = new List<int>();
                            parentDic.Add(parentIndex - 1,children);
                        }
                        children.Add(i);
                    }

                    int skillPriority = 0;
                    int skillCd = 0;
                    int skillBornCd = 0;
                    var sp = levelConfig.GetValueFromArray(levelConfig.monster_skill_priority, i);
                    skillPriority = sp.x;
                    skillCd = sp.y;
                    skillBornCd = sp.z;


                    int stageId = levelConfig.GetValueFromArray(levelConfig.monster_wave, i);
                    var enemy = new EnemySpawn
                    {
                        id = id,
                        stageId = stageId,
                        positionId = placeIndex,
                        level = level,
                        position = position,
                        param = time,
                        type = 1,
                        hasSpawned = false,
                        specialObjectConfig = specialObjectConfig,
                        childList = childList,
                        team = team,
                        skillPriority = skillPriority,
                        skillCd = skillCd,
                        skillBornCd = skillBornCd,
                    };
                    if (parentIndex != 0)
                    {
                        enemy.hasParent = true;
                        enemy.type = 999;
                    }
                    enemys.Add(enemy);
                }

                foreach (var parent in parentDic)
                {
                    var p = enemys[parent.Key];
                    var children = parent.Value;
                    for (int i = 0; i < children.Count; i++)
                    {
                        p.childList.Add(children[i]);
                    }
                }

                this.enemys.Add(0,enemys);
                this.stages.Add(new StageSpawn
                {
                    id = 0,
                    hasSpawned = false,
                    stageType = 0,
                    stageParam = 0,
                    previousStage = 0,
                });
            }
        }

        public void StartTest(int index)
        {
            GetMapTest(index,currentPosition);
        }

        private GameObject rpgLight;
        private GameObject levelRpgLight;
        private int levelRpgLightIndex;
        public static LightController rpgLightController;
        public static RpgModelShadowController rpgModelShadowController;
        private GameObject obstacleLight;
        private bool originFog;
        private Color originFogColor;
        private FogMode originFogMode;
        private float originFogStart;
        private float originFogEnd;
        private LightmapData[] originLightMap;
        private List<Texture2D> lightMapColors;

        public void CreateModelLight(bool isRpg)
        {
            if (isRpg) {
                rpgLight = HRPHelper.RpgRenderScene.transform.Find("ShaderSetting").gameObject;
                rpgLightController = HRPHelper.RpgRenderScene.transform.GetComponentInChildren<LightController>(true);
            }
            else {
                rpgLight = HRPHelper.PveRenderScene.transform.Find("ShaderSetting").gameObject;
                rpgLightController = HRPHelper.PveRenderScene.transform.GetComponentInChildren<LightController>(true);
            }
        }

        public void CreateModelLightToNewScene(Transform parent)
        {
            var lightObjectTrans = parent.Find("ShaderSetting");
            GameObject lightObject;
            if (lightObjectTrans == null)
            {
                lightObject = GameObject.Instantiate(HRPHelper.RpgRenderScene.transform.Find("ShaderSetting").gameObject, parent);
                var renderScene = parent.GetComponent<HBaseRenderScene>();
                renderScene.RenderLights = new List<Light>();
                var lights = lightObject.GetComponentsInChildren<Light>(true);
                for (int i = 0; i < lights.Length; i++)
                {
                    lights[i].cullingMask = 0;
                    renderScene.RenderLights.Add(lights[i]);
                }
            }
            else
            {
                lightObject = lightObjectTrans.gameObject;
            }
            
            if (lightObject)
            {
                rpgLight = lightObject;
                rpgLightController = lightObject.GetComponentInChildren<LightController>(true);
            }
        }

        private Light keyLight;

        private float hangLightIntensity = 1.6f;
        
        public void HangLightToRpg()
        {
            if (rpgLight != null)
            {
                var keyLightObj = rpgLight.transform.Find("Key");
                if (keyLightObj != null)
                {
                    var keyLight = keyLightObj.GetComponent<Light>();
                    hangLightIntensity = keyLight.intensity;
                    keyLight.intensity = 2f;
                }
            }
        }

        public void RpgLightToHang()
        {
            if (rpgLight != null)
            {
                var keyLightObj = rpgLight.transform.Find("Key");
                if (keyLightObj != null)
                {
                    var keyLight = keyLightObj.GetComponent<Light>();
                    keyLight.intensity = hangLightIntensity;
                }
            }
        }
        
        private GameObject rpgMusic;
        private int lastRpgMusicIndex;

        private GameObject rpgBossMusic;
        private int lastRpgBossIndex;

        private GameObject hangMusic;
        private int lastHangMusicIndex;
        public void StartRpgMusic()
        {
            StopHangMusic();
            StopBossMusic();
            int battle_model_res = 1;
            var rpgLevelMonster = PveUtils.GetRpgLevelMonsterConfig(PveManager.Instance.RpgLevelId);
            if (rpgLevelMonster != null)
            {
                battle_model_res = rpgLevelMonster.battle_model_res;
            }

            lastRpgMusicIndex = battle_model_res;
            if (rpgMusic != null)
            {
                PveResourceManager.RecoverResource(rpgMusic,PveResourceManager.EPveResType.Music,lastRpgMusicIndex);
            }

            rpgMusic = PveResourceManager.GetResource(PveResourceManager.EPveResType.Music, battle_model_res);
            if (rpgMusic != null)
            {
                rpgMusic.transform.SetParent(PveScene.pveRootTrans);
            }
            //PveResourceManager.RecoverResource(levelRpgLight,PveResourceManager.EPveResType.LightingSetting,levelRpgLightIndex);
        }

        public void StopRpgMusic()
        {
            StopBossMusic();
            if (rpgMusic != null)
            {
                PveResourceManager.RecoverResource(rpgMusic,PveResourceManager.EPveResType.Music,lastRpgMusicIndex);
                rpgMusic = null;
            }
        }

        public void PlayBossMusic()
        {
            lastRpgBossIndex = 101;
            if (rpgBossMusic != null)
            {
                PveResourceManager.RecoverResource(rpgBossMusic,PveResourceManager.EPveResType.Music,lastRpgBossIndex);
            }
            rpgBossMusic = PveResourceManager.GetResource(PveResourceManager.EPveResType.Music, lastRpgBossIndex);
            rpgBossMusic.transform.SetParent(PveScene.pveRootTrans);
        }

        public void StopBossMusic()
        {
            if (rpgBossMusic != null)
            {
                PveResourceManager.RecoverResource(rpgBossMusic,PveResourceManager.EPveResType.Music,lastRpgBossIndex);
                rpgBossMusic = null;
            }
        }

        public void PlayHangMusic()
        {
            // 判断新手引导???
            //
            lastHangMusicIndex = 102;
            if (hangMusic == null)
            {
                hangMusic = PveResourceManager.GetResource(PveResourceManager.EPveResType.Music, lastHangMusicIndex);
                hangMusic.transform.SetParent(PveScene.pveRootTrans);
            }
            if (hangMusic != null)
            {
                hangMusic.SetActive(false);
                hangMusic.SetActive(true);
            }
        }

        public void StopHangMusic()
        {
            if (hangMusic != null)
            {
                hangMusic.SetActive(false);
            }
        }

        public void SetShadowDistance(float shadowDistance)
        {
            UniversalRenderPipelineAsset pipelineAsset = (UniversalRenderPipelineAsset)GraphicsSettings.currentRenderPipeline;
            pipelineAsset.shadowDistance = shadowDistance;
        }
        
        public void HideHangingLight()
        {
            if (hangRenderSetting == null)
            {
                hangRenderSetting = GameObject.Find("RPG_Level01_Revise_Settings");
            }

            if (hangRenderSetting != null)
            {
                hangRenderSetting.SetActive(false);
            }
            
//            UniversalRenderPipelineAsset pipelineAsset = (UniversalRenderPipelineAsset)GraphicsSettings.currentRenderPipeline;
//            pipelineAsset.shadowDistance = 40;
//            pipelineAsset.shadowDepthBias = 0;
        }

        public void ShowHangingLight()
        {
            if (hangRenderSetting == null)
            {
                hangRenderSetting = GameObject.Find("RPG_Level01_Revise_Settings");
            }

            if (hangRenderSetting != null)
            {
                hangRenderSetting.SetActive(true);
            }
            
//            UniversalRenderPipelineAsset pipelineAsset = (UniversalRenderPipelineAsset)GraphicsSettings.currentRenderPipeline;
//            pipelineAsset.shadowDistance = 20;
//            pipelineAsset.shadowDepthBias = 0.15f;
        }

        private GameObject hangRenderSetting;
        private GameObject rpgRenderSetting;

        public void SwitchToRpgRenderSetting()
        {
            HideHangingLight();
            if (rpgRenderSetting == null)
            {
                rpgRenderSetting = PveResourceManager.GetResource(PveResourceManager.EPveResType.RenderSetting, 1);
            }

            if (rpgRenderSetting != null)
            {
                rpgRenderSetting.transform.SetParent(PveScene.pveRootTrans);
                rpgRenderSetting.SetActive(true);
                var renderSetting = rpgRenderSetting.transform.Find("rendersetting");
                if (renderSetting != null)
                {
                    var esc = renderSetting.GetComponent<HEnvironmentSettingsComponent>();
                    if (esc)
                    {
                        esc.enabled = false;
                    }
                    var alsc = renderSetting.GetComponent<HAmbientLightSettingsComponent>();
                    if (alsc)
                    {
                        alsc.enabled = false;
                    }
                    var slsc = renderSetting.GetComponent<HSceneLightSettingsComponent>();
                    if (slsc)
                    {
                        slsc.enabled = false;
                        if (keyLight != null)
                        {
                            slsc.data.mainLight = keyLight;
                            slsc.data.mainShadowLight = keyLight;
                        }
                    }

                    TimeManager.Instance.DelayCall(100, () =>
                    {
                        if (esc)
                        {
                            esc.enabled = true;
                        }
                        if (alsc)
                        {
                            alsc.enabled = true;
                        }
                        if (slsc)
                        {
                            slsc.enabled = true;
                        }
                    },true);
                }
                var volume = rpgRenderSetting.transform.Find("Global Volume");
                if (volume != null)
                {
                    var vc = volume.GetComponent<Volume>();
                    if (vc != null)
                    {
                        vc.enabled = true;
                    }
                }
            }
        }

        public void SwitchToHangRenderSetting()
        {
            if (rpgRenderSetting != null)
            {
                rpgRenderSetting.SetActive(false);
            }
            ShowHangingLight();
        }
        
        public void StartRPGFromPve()
        {
            //obstacleLight.SetActive(true);
        }

        public void StartRPG(Vector3 position)
        {
            /*CreateModelLight();
            currentOffset = Vector3.zero;
            SaveOriginSceneSettings();
            ApplyLightMap();
            CreateMapSegment(currentPosition,0);
            CreateMapSegment(currentPosition + new Vector3(50,0,0),1);*/
            preloadMapCount = 0;
            SaveOriginSceneSettings();
            ApplyLightMap();
            ApplyFog();
            currentPosition = position;
            rpgPosition = position;
            InitRpgData();
            CreateMapSegment(currentPosition,0);
            /*CreateMapSegment(currentPosition,1);
            CreateMapSegment(currentPosition,2);
            CreateMapSegment(currentPosition,3);
            CreateMapSegment(currentPosition,4);*/
        }

        private void SaveOriginSceneSettings()
        {
            originLightMap = LightmapSettings.lightmaps;
            originFog = RenderSettings.fog;
            originFogColor = RenderSettings.fogColor;
            originFogMode = RenderSettings.fogMode;
            originFogStart = RenderSettings.fogStartDistance;
            originFogEnd = RenderSettings.fogEndDistance;
        }
        
        private GameObject refrectionProbe;
        
        private void ApplyLightMap()
        {
            var lightMapColors = PveResourceManager.GetLightMapColor();
            var lightMapDirs = PveResourceManager.GetLightMapDir();
            this.lightMapColors = lightMapColors;
            var sceneLightMap = new LightmapData[lightMapColors.Count];
            for (int i = 0; i < sceneLightMap.Length; i++)
            {
                sceneLightMap[i] = new LightmapData
                {
                    lightmapColor = lightMapColors[i],
                    lightmapDir = lightMapDirs[i],
                };
            }

            LightmapSettings.lightmaps = sceneLightMap;
            LightmapSettings.lightmapsMode = LightmapsMode.CombinedDirectional;
            //RenderSettings.skybox = PveResourceManager.GetSkyBoxMaterial();
            RenderSettings.ambientLight = PveResourceManager.GetAmbientColor();
            RenderSettings.defaultReflectionMode = PveResourceManager.GetReflectionMode();
            RenderSettings.ambientSkyColor = PveResourceManager.GetAmbientColor();

            if (refrectionProbe != null)
            {
                GameObject.DestroyImmediate(refrectionProbe);
                refrectionProbe = null;
            }
            
            var cubeMap = PveResourceManager.GetReflectionProbe();
            if (cubeMap != null)
            {
                RenderSettings.customReflection = cubeMap;
                refrectionProbe = new GameObject("ReflectionProbe");
                refrectionProbe.transform.position = currentPosition;
                var rp = refrectionProbe.AddComponent<ReflectionProbe>();
                rp.customBakedTexture = cubeMap;
                rp.mode = ReflectionProbeMode.Custom;
                rp.size = new Vector3(1000, 1000, 1000);
            }
            //LightmapSettings.lightmapsMode = LightmapsMode.NonDirectional;
        }

        private void ApplyFog()
        {
            var sceneConfig = PveResourceManager.GetPveSceneConfig();
            RenderSettings.fog = sceneConfig.RenderData.isFog;
            RenderSettings.fogColor = sceneConfig.RenderData.fogColor;
            RenderSettings.fogMode = sceneConfig.RenderData.fogMode;
            RenderSettings.fogStartDistance = sceneConfig.RenderData.fogStart;
            RenderSettings.fogEndDistance = sceneConfig.RenderData.fogEnd + 250;
            
            UnityEngine.Debug.Log("ApplyFog....");
        }

        private Dictionary<int, GameObject> stageMapDic = new Dictionary<int, GameObject>();

        private Dictionary<int,Vector3> rpgMapSegmentPositions = new Dictionary<int,Vector3>();

        private int mapSegmentCount = 2;

        public void SaveRpgMapSegment()
        {
            rpgMapSegmentPositions.Clear();
            foreach (var item in stageMapDic)
            {
                rpgMapSegmentPositions.Add(item.Key,item.Value.gameObject.transform.position + new Vector3(0,0.1f,0));
            }
        }

        private void LoadRpgMapSegment()
        {
            m_gpuInfos.Clear();
            foreach (var item in stageMapDic)
            {
                PveResourceManager.RecoverPveSceneMapPrefab(item.Value, 0,item.Key % mapSegmentCount);
            }
            stageMapDic.Clear();
            foreach (var item in rpgMapSegmentPositions)
            {
                CreateMapSegment(item.Value,item.Key);
            }
        }

        private void AddSideBuilding(int stageId,Transform parent)
        {
            var sideBuildings = new List<GameObject>();
            pveSideBuildings.Add(stageId,sideBuildings);
            for (int i = 0; i < parent.childCount; i++)
            {
                var child = parent.GetChild(i);
                if (child.name.Contains("jianzhu"))
                {
                    var newBuilding = GameObject.Instantiate(child.gameObject);
                    sideBuildings.Add(newBuilding);

                }
            }

            for (int i = 0; i < sideBuildings.Count; i++)
            {
                var newBuilding = sideBuildings[i];
                newBuilding.transform.SetParent(parent);
                newBuilding.transform.localEulerAngles = new Vector3(0,180,0);
                newBuilding.transform.localPosition = new Vector3(0, 0, 3.25f);
            }
        }

        private void RemoveSideBuilding(int stageId)
        {
            if (pveSideBuildings.TryGetValue(stageId,out var list))
            {
                for (int i = 0; i < list.Count; i++)
                {
                    GameObject.Destroy(list[i]);
                }
                pveSideBuildings.Remove(stageId);
            }
        }

        public void RemoveSideBuildings()
        {
            foreach (var item in pveSideBuildings)
            {
                var list = item.Value;
                for (int i = 0; i < list.Count; i++)
                {
                    GameObject.Destroy(list[i]);
                }
            }
            pveSideBuildings.Clear();
        }

        private Dictionary<int, List<GameObject>> pveSideBuildings = new Dictionary<int, List<GameObject>>();

        private void CreateMapSegment(Vector3 currentPosition,int stageId)
        {
//            var map = PveResourceManager.GetPveSceneMapPrefab(stageId % mapSegmentCount);
//            if (map == null)
//            {
//                return;
//            }
//            map.transform.SetParent(root.transform);
//            map.transform.position = currentPosition - new Vector3(0,0.1f,0);
//            map.SetActive(true);
//            /*if (PveManager.Instance.isInPve)
//            {
//                AddSideBuilding(stageId,map.transform);
//            }*/
//            if (isInLargeMap)
//            {
//                //map.transform.position = currentPosition + new Vector3(0, 1, 0);
//                //map.transform.localEulerAngles = new Vector3(0,0,-1.45f);
//            }
//            stageMapDic.Add(stageId,map);
//            var gpuList = PveResourceManager.GetPveSceneGpuData();
//            for (int i = 0; i < gpuList.Count; i++)
//            {
//                if (gpuList[i].material == null || gpuList[i].mesh == null)
//                {
//                    continue;
//                }
//                int tempCount = gpuList[i].objs.Count;
//                if (tempCount == 0)
//                {
//                    continue;
//                }
//                gpuInstanceInfo gpuInfo = new gpuInstanceInfo();
//                gpuInfo.properties = new MaterialPropertyBlock();
//                gpuInfo.mesh = gpuList[i].mesh;
//                gpuInfo.mat = gpuList[i].material;
//                List<Matrix4x4> matrixList = new List<Matrix4x4>();
//                int lightmapIndex = 0;
//                List<Vector4> ltmapUV = new List<Vector4>();
//                for (int j = 0; j < tempCount; j++)
//                {
//                    SSceneConfig.SceneObj obj = gpuList[i].objs[j];
//                    lightmapIndex = obj.lightmapIndex;
//                    ltmapUV.Add(obj.lightmapScaleOffset);
//                    Matrix4x4 localToWorldMatrix = new Matrix4x4(new Vector4(obj.m00, obj.m10, obj.m20, obj.m30), new Vector4(obj.m01, obj.m11, obj.m21, obj.m31), new Vector4(obj.m02, obj.m12, obj.m22, obj.m32), new Vector4(obj.m03 + currentPosition.x, obj.m13 + currentPosition.y - 0.1f, obj.m23 + currentPosition.z, obj.m33));
//                    Vector3 scale = localToWorldMatrix.lossyScale;
//                    if (scale.x < 0.0f || scale.y < 0.0f || scale.y < 0.0f)
//                        Debug.LogError("Has Negative Scale: " + obj.name);
//                    matrixList.Add(localToWorldMatrix);
//                }
//                if (lightMapColors.Count > lightmapIndex)
//                {
//                    gpuInfo.mat.SetTexture(Uniforms._LtMap, lightMapColors[lightmapIndex]);
//                }
//                gpuInfo.properties.SetVectorArray(Uniforms._ltmapUV, ltmapUV);
//                gpuInfo.matrixArray = matrixList.ToArray();
//                gpuInfo.stageId = stageId;
//                m_gpuInfos.Add(gpuInfo);
//            }
//
//            map.SetLayerRecursively(LayerMask.NameToLayer("PveMap"));
//
//            var meshRenderers = map.GetComponentsInChildren<MeshRenderer>();
//            for (int i = 0; i < meshRenderers.Length; i++)
//            {
//                var mr = meshRenderers[i];
//                if (mr.sharedMaterial.shader.name.Contains("GTA_RPG_Sence_DirLight_LM"))//建筑
//                {
//                    mr.gameObject.GetOrAddComponent<BoxCollider>();
//                    var hashCode = meshRenderers[i].gameObject.GetHashCode();
//                    mapObjects[hashCode] = new MapObject
//                    {
//                        alpha = 1,
//                        targetAlpha = 1,
//                        gameOject = meshRenderers[i].gameObject,
//                        originMat = meshRenderers[i].sharedMaterial,
//                        meshRenderer = mr,
//                    };
//                }
//
//            }
        }

        private GameObject front;
        private GameObject back;

        private PveMapData pveData;
        public RpgBattleRegion currentRpgRegion;

        //gpuInstancing
        private struct gpuInstanceInfo
        {
            public bool bNegativeScale;
            public Mesh mesh;
            public Material mat;
            public Matrix4x4[] matrixArray;
            public MaterialPropertyBlock properties;
            public int layer;
            public int stageId;
        }
        private List<gpuInstanceInfo> m_gpuInfos = new List<gpuInstanceInfo>();

        private Dictionary<int,MapObject> mapObjects = new Dictionary<int, MapObject>();

        private class MapObject
        {
            public GameObject gameOject;
            public MeshRenderer meshRenderer;
            public Material originMat;
            public Material alphaMat;
            public float alpha;
            public float targetAlpha;
        }

        public void Update()
        {
            for (int i = 0; i < m_gpuInfos.Count; i++)
            {
                Graphics.DrawMeshInstanced(m_gpuInfos[i].mesh, 0, m_gpuInfos[i].mat, m_gpuInfos[i].matrixArray, m_gpuInfos[i].matrixArray.Length, m_gpuInfos[i].properties, UnityEngine.Rendering.ShadowCastingMode.Off, false, m_gpuInfos[i].layer);
            }

            if (skyBox != null)
            {
                var position = PveCameraManager.Instance.cameraTrans.transform.position;
                var diff = position - cameraPosition;
                diff.y = 0;
                skyBox.transform.position += diff;
                cameraPosition = position;
            }
            CheckNeedCull();

        }

        private void CheckNeedCull()
        {
            var hits = Physics.RaycastAll(PveCameraManager.Instance.mainCamera.transform.position,
                PveCameraManager.Instance.mainCamera.transform.forward,8,1 << LayerMask.NameToLayer("PveMap"));
            foreach (var item in mapObjects.Values)
            {
                item.targetAlpha = 1;
            }
            for (int i = 0; i < hits.Length; i++)
            {
                MapObject obj;
                int id = hits[i].transform.gameObject.GetHashCode();
                if (mapObjects.TryGetValue(id, out obj))
                {
                    obj.targetAlpha = 0.3f;
                    if (obj.alphaMat == null)
                    {
                        obj.alphaMat = Object.Instantiate(obj.originMat);
                        obj.meshRenderer.sharedMaterial = obj.alphaMat;
                        obj.alphaMat.SetFloat("_Alpha",obj.targetAlpha);
                        obj.alphaMat.renderQueue = 3000;
                    }
                }
            }

            foreach (var item in mapObjects.Values)
            {
                if (item.targetAlpha == 1 && item.alphaMat != null)
                {
                    item.meshRenderer.sharedMaterial = item.originMat;
                    GameObject.Destroy(item.alphaMat);
                    item.alphaMat = null;
                }
            }
        }

        private int preloadMapCount = 0;

        public void InitPveMapData()
        {
            pveData = PveResourceManager.Instance.GetPveMapData(5);
            var blocks = new List<List<bool>>();
            for (int i = 0; i < pveData.width; i++)
            {
                var list = new List<bool>();
                for (int j = 0; j < pveData.height; j++)
                {
                    list.Add(pveData.blocks[i * pveData.height + j]);
                }
                blocks.Add(list);
            }
            PveFindPathManager.Instance.AddStaticBlocks(blocks,currentPosition + pveData.blocksOffset);
            /*var tempMap = PveResourceManager.GetResource(PveResourceManager.EPveResType.Map, 100);
            tempMap.transform.SetParent(root.transform);
            tempMap.transform.position = currentPosition;*/
        }

        public static bool isInLargeMap = false;
        private int mapResourceId;

        private PveMapPoint currentPoint;
        private PveMapPoint nextPoint;

        private GameObject skyBox;
        private Vector3 cameraPosition;

        //挂机地图
        public void StartPve(Vector3 currentPosition)
        {
            this.currentPosition = currentPosition;
            this.nextPosition = currentPosition + GetPositionOffsetByDirection(EMapDirection.right);
            myGotoPosition = GetPositionOffsetByDirection(EMapDirection.right);
            SaveOriginSceneSettings();
            ApplyLightMap();
            ApplyFog();
           //TODO:注掉先
            // InitMapQueue();
            /*CreateMapSegment(currentPosition,0);
            for (int i = 1; i <= preloadMapCount; i++)
            {
                CreateMapSegment(currentPosition + new Vector3(50 * i,0,0),i);
            }*/

            skyBox = PveResourceManager.GetSkyBoxObject();
            if (skyBox != null)
            {
                skyBox.transform.SetParent(PveScene.pveRootTrans);
                skyBox.transform.position = new Vector3(100,100,20.6f) + currentPosition;
                skyBox.SetActive(true);
            }

            cameraPosition = PveCameraManager.Instance.mainCamera.transform.position;

            //skyBox.transform.localPosition += PveCameraManager.Instance.mainCamera.transform.position;
            //skyBox.transform.localPosition = new Vector3(0,0,0);
            //skyBox.transform.localScale = new Vector3(10f, 10 ,10);

            //currentRegion = pveData.regions[0];
            //obstacleLight.SetActive(true);
           //TODO:注掉先
            // CheckMap();

            var maproot = this.GetSceneRootPrefab();
            maproot.transform.SetParent(this.root.transform);

        }


        private int GetIndexByOffset(Vector3 offset)
        {
            return (int)offset.x * 1000000 + (int)offset.z;
        }

        private MapObj GetMap(Vector3 position,EMapDirection require,Vector3 offset, EMapDirection requireOut = EMapDirection.none,EMapDirection notOnly = EMapDirection.none)
        {
            if (aroundMapData.TryGetValue(GetIndexByOffset(offset), out var mapData))
            {
                return mapData;
            }
            List<MapData> candidates = new List<MapData>();
            foreach(var item in mapList.Values)
            {
                if (item.CheckIsValid(require,requireOut, notOnly))
                {
                    candidates.Add(item);
                }
            }

            if (candidates.Count > 0)
            {
                var data = candidates[Random.Range(0,candidates.Count)];
                var map = CreateMapAndObjects(data);
                map.transform.position = position;
                map.name = offset.ToString();
                if (data.index == 7)
                {
                    map.transform.localEulerAngles = new Vector3(0,-90,0);
                }
                var mapObj = new MapObj
                {
                    map = map,
                    from = require,
                    index = data.index,
                    offset = offset,
                };
                aroundMapData.Add(GetIndexByOffset(offset),mapObj);
                return mapObj;
            }
            return default;
        }

        private MapObj GetCertainMap(Vector3 position,Vector2 offset,int index,EMapDirection from)
        {
            if (aroundMapData.TryGetValue(GetIndexByOffset(offset), out var mapData))
            {
                return mapData;
            }
            var data = mapList[index];
            var map = CreateMapAndObjects(data);
            map.transform.position = position;
            if (index == 7)
            {
                map.transform.localEulerAngles = new Vector3(0,-90,0);
            }
            map.name = offset.ToString();
            var mapObj = new MapObj
            {
                map = map,
                from = from,
                index = data.index,
                offset = offset,
            };
            aroundMapData.Add(GetIndexByOffset(offset),mapObj);
            return mapObj;
        }

        private MapObj GetMapTest(int index,Vector3 position)
        {
            var map = CreateMapAndObjects(mapList[index]);
            map.transform.position = position;
            var mapObj = new MapObj
            {
                map = map,
                index = index,
            };
            return mapObj;
        }

        //创建地块和他的子物体
        private GameObject CreateMapAndObjects(MapData data)
        {
            GameObject root = new GameObject("Map"+data.index);
            root.transform.SetParent(this.root.transform);
            if (data.objData.gameObject == null)
            {
                return root;
            }
            var map = GameObject.Instantiate(data.objData.gameObject,root.transform);
            map.transform.SetActive(true);
            map.transform.localScale = PveUtils.globalRatio * 2.5f * new Vector3(1, 1, 1);
            map.transform.localPosition = Vector3.zero;
            for (int i = 0; i < data.objData.subObjects.Count; i++)
            {
                var obj = GameObject.Instantiate(data.objData.subObjects[i],root.transform);
                obj.transform.localPosition = PveUtils.globalRatio * 2.5f * data.objData.subObjectPositions[i];
                obj.transform.forward = data.objData.subObjectForwards[i];
                obj.transform.localScale = PveUtils.globalRatio * 2.5f * data.objData.subObjectScales[i];
                obj.SetActive(true);
            }

            root.transform.position = data.objData.position;
            return root;
        }

        private int pveMapCount = 0;
        

        public void StagePrepare()
        {

        }

        private int lastStageId;

        private float lastCrossY;
        private int mapCheckId;
        private int roadCheckId;
        private int currentIndexId;

        private void CheckMap()
        {
            //Debug.LogError("changeMap" + this.mapCheckId);
            //Debug.LogError("point" + pveData.points[this.mapCheckId].position);
            var destroyList = new List<int>();
            foreach (var item in stageMapDic)
            {
                destroyList.Add(item.Key);
            }
            for (int i = 0; i < pveData.points[this.mapCheckId].mapList.Count; i++)
            {
                int id = pveData.points[this.mapCheckId].mapList[i];
                if (!stageMapDic.ContainsKey(id))
                {
                    CreateMapSegment(nextMapPosition,id);
                }
                destroyList.Remove(id);
            }
            for (int i = 0; i < destroyList.Count; i++)
            {
                var clearStageId = destroyList[i];
                if (stageMapDic.TryGetValue(clearStageId, out var map))
                {
                    PveResourceManager.RecoverPveSceneMapPrefab(map, mapResourceId,clearStageId % mapSegmentCount);
                    stageMapDic.Remove(clearStageId);
                }
            }
        }
        private Queue<queueObject> mapIndexQueue = new Queue<queueObject>(3){};
        private Queue<roadQueueObject> roadInfoQueue = new Queue<roadQueueObject>(2) { };
        class queueObject
        {
            public int index;
            public int part;
            public GameObject prefab;
        }

        class roadQueueObject
        {
            public int index;
            public GameObject path;
        }
        private void InitMapQueue()
        {
    
            mapIndexQueue.Clear();
            MapEnqueue(0);
            MapEnqueue(1);
            MapEnqueue(2);
            //MapEnqueue(2);
            //MapEnqueue(2);
            InitRoad();
            RebuildNavMesh(false);
            
           // AddNpc(0,true);
            this.mapCheckId = 0;
            roadCheckId = 0;
        }

        public void ResetMapQueueByCurrentPosition(Vector3 checkPosition,System.Action action = null)
        {
            //int currentIndex = Mathf.FloorToInt((checkPosition.x - 100) / (122 * 0.33f));
            //this.mapCheckId = currentIndex;
            //roadCheckId = Mathf.FloorToInt((checkPosition.x - 100) / 122f);
            //MapDequeueAll();
            //mapIndexQueue.Clear();
            //MapEnqueue(this.mapCheckId);
            //MapEnqueue(this.mapCheckId + 1);
            //MapEnqueue(this.mapCheckId + 2);
            //ConnectRoad();
            //AddNpc(roadCheckId, true);
            //RPGTreeBehaviors.Instance.SetMainCharactorBornIndex(checkPosition);
            //DynamicNavMeshBuilder.Instance.StartCoroutine(WaitAFrame(action));

        }

        private IEnumerator WaitAFrame(System.Action action)
        {
            yield return new WaitForEndOfFrame();
            DynamicNavMeshBuilder.Instance.enabled = true;
            action?.Invoke();
        }
        private void InitRoad()
        {
            RoadInQueue(0);
            RoadInQueue(1);
        }

        private void RoadInQueue(int index)
        {
            GameObject points = PveResourceManager.Instance.GetPathPoints();

            roadInfoQueue.Enqueue(new roadQueueObject()
            {
                index = index,
                path = points
            });
            var position = new Vector3(100 + Mathf.Abs(index) * 122f, -0.1f, 100f);
            points.transform.position = position;
        }

        private void RoadDequeue()
        {
            var roadInfo = roadInfoQueue.Dequeue();
            PveResourceManager.Instance.RecoverPathPoints(roadInfo.path);
        }

        private void MapEnqueue(int index)
        {
            for (int i = 0; i < 3; i++)
            {
                int part = i * 3 + (index % 3);
                var prefab = GetScenePrefab(part, index);

                var queueObj = new queueObject()
                {
                    prefab = prefab,
                    index = index,
                    part = part
                };
                mapIndexQueue.Enqueue(queueObj);
            }
        }

        public GameObject GetSceneRootPrefab()
        {
            var prefab = PveResourceManager.GetPveSceneMapPrefab();
            return prefab;
        }
        private GameObject GetScenePrefab(int part,int index)
        {
            var prefab = PveResourceManager.GetPveSceneMapPrefab(part);
            prefab.name = "Map   " + "index;" + index + "part:" + part;
            int posIndex = index / 3;
            prefab.gameObject.transform.position = new Vector3(100 + 122 * posIndex, -0.1f, 100f);
            prefab.transform.SetParent(root.transform);
            return prefab;
        }

        private void MapDequeue()
        {
            var queueObj =  mapIndexQueue.Dequeue();
            PveResourceManager.RecoverPveSceneMapPrefab(queueObj.prefab, queueObj.index, queueObj.part);
        }

        public void UnloadPveResource()
        {
            MapDequeueAll();
            PveResourceManager.Instance.UnloadPveResource();
        }
        private void MapDequeueAll()
        {
            var length = mapIndexQueue.Count;
            for (int i = 0; i < length; i++)
            {
                MapDequeue();
            }
        }

        public void CheckNeedLoadNextMap(Vector3 checkPosition)
        {
            int index = Mathf.FloorToInt((checkPosition.x - 100) / (122f * 0.33f));

            bool needRefresh = false;
            int mapCheckId = this.mapCheckId;
            int roadInfoIndex = Mathf.FloorToInt((checkPosition.x - 100) / (122f));

            if (roadInfoIndex!= roadCheckId)
            {
                RoadDequeue();
                RoadInQueue(roadInfoIndex + 1);
                roadCheckId = roadInfoIndex;
            }
            if (index != mapCheckId)
            {
                MapDequeue();
                MapDequeue(); 
                MapDequeue();
                MapEnqueue(index + 2);
                var oldPos = PveManager.Instance.mainUnit.Data.position;
                //PveManager.Instance.mainUnit.Data.position = new Vector3(oldPos.x, oldPos.y, oldPos.z - 122);
                //PveManager.Instance.mainUnit.gameObject.transform.position = new Vector3(oldPos.x, oldPos.y, oldPos.z - 122);
                ResetNpcGeneratePointCD();
                RebuildNavMesh(true,() =>
                {
                    
                });
                this.mapCheckId = index;
            }
        }

        private void ResetNpcGeneratePointCD()
        {
            
        }

        private void RebuildNavMesh(bool asyncUpdate,System.Action action = null)
        {
            DynamicNavMeshBuilder.Instance.ReBuildMesh(asyncUpdate,action);
        }


        public Vector3 GetNpcBirthPosition()
        {
            var points = pveData.peoplePoint;
            var pointsIndex = Random.Range(0, points.Count);
            return points[pointsIndex];
        }
        public void LoadNextMap(int stageId)
        {
            //if (!isInLargeMap)
            {
                ClearMap(stageId);
            }
            var stage = (int)(stageId / mapSegmentCount);
            if (stage > lastStageId)
            {
                currentMapPosition += new Vector3(122,0,0);
            }
            // + GetPositionOffsetByDirection(EMapDirection.right);
            myGotoPosition = GetPositionOffsetByDirection(EMapDirection.right);
            if (!isInLargeMap)
            {
                CreateMapSegment(currentMapPosition,stageId + preloadMapCount);
            }

            lastStageId = stage;
            this.nextPosition = nextPosition;
        }


        private List<Vector3> sandPositions = new List<Vector3>
        {
            new Vector3(85,0,100),
            new Vector3(100,0,115),
            new Vector3(115,0,100),
            new Vector3(100,0,85),
        };

        private int nextSandIndex;


        private int GetGraphIndex(int team)
        {
            return currentMapData.index * 1000 + team;
        }

        private void ClearMap(int stageId)
        {
            int clearStageId = stageId - 2;
            var list = new List<gpuInstanceInfo>();
            for (int i = 0; i < m_gpuInfos.Count; i++)
            {
                if (m_gpuInfos[i].stageId != clearStageId)
                {
                    list.Add(m_gpuInfos[i]);
                }
            }
            m_gpuInfos = list;

            if (stageMapDic.TryGetValue(clearStageId, out var mapPrefab))
            {
                RemoveSideBuilding(clearStageId);
                PveResourceManager.RecoverPveSceneMapPrefab(mapPrefab, mapResourceId,clearStageId % mapSegmentCount);
                stageMapDic.Remove(clearStageId);
            }
        }

        private EMapDirection GetOppositeDir(EMapDirection from)
        {
            if (from == EMapDirection.bottom)
            {
                return EMapDirection.top;
            }

            if (from == EMapDirection.left)
            {
                return EMapDirection.right;
            }

            if (from == EMapDirection.top)
            {
                return EMapDirection.bottom;
            }

            if (from == EMapDirection.right)
            {
                return EMapDirection.left;
            }

            return EMapDirection.none;
        }

        private List<EMapDirection> nextStart = new List<EMapDirection>();
        private EMapDirection nextBattleStart;

        private void LoadAroundMap(bool ignoreFrom = true)
        {
            nextStart.Clear();
            var centerCandidates = new List<EMapDirection>();//过渡房间的开始入口
            var nextCandidates = new List<EMapDirection>();
            var currentData = mapList[currentMapData.index];
            foreach (var dir in currentData.directionInfo)
            {
                if (dir.Value && !(currentMapData.from == dir.Key && ignoreFrom))
                {
                    var opp = GetOppositeDir(dir.Key);
                    nextStart.Add(opp);
                    if (opp != requiredOut && currentMapData.from != dir.Key)
                    {
                        centerCandidates.Add(opp);
                    }
                }
            }

            /*var centerDir = EMapDirection.none;
            if (centerCandidates.Count > 0)
            {
                centerDir = centerCandidates[Random.Range(0, centerCandidates.Count)];
                rpgCenterDir = centerDir;
            }
            else
            {
                Debug.LogError("没有找到过度房间");
                foreach (var item in nextStart)
                {
                    Debug.LogError(item);
                }
            }*/

            for (int i = 0; i < nextStart.Count; i++)
            {
                var nextStartDir = nextStart[i];
                var dir = GetOppositeDir(nextStartDir);
                var nextForward = GetDirection(dir);
                Vector3 nextPosition = currentPosition + GetPositionOffsetByDirection(dir);
                Vector3 offset = currentOffset + nextForward;
                var requiredOut = EMapDirection.none;
                /*if (nextStartDir == centerDir)
                {
                    requiredOut = this.requiredOut;
                }*/
                MapObj aroundMap = GetMap(nextPosition, nextStartDir, offset,requiredOut,GetOppositeDir(this.requiredOut));
                var aroundData = mapList[aroundMap.index];
                if (aroundData.CheckIsValid(GetOppositeDir(nextStartDir)))
                {
                    LoadNextMapByDirection(GetOppositeDir(nextStartDir),currentOffset + nextForward,nextPosition,requiredOut,GetOppositeDir(this.requiredOut));
                }
            }
        }

        private void LoadNextMapByDirection(EMapDirection targetDirection,Vector3 offset,Vector3 position,EMapDirection requiredOut = EMapDirection.none,EMapDirection notOnly = EMapDirection.none)
        {
            var nextDir = GetDirection(targetDirection);
            GetMap(position + GetPositionOffsetByDirection(targetDirection), GetOppositeDir(targetDirection), offset + nextDir,requiredOut,notOnly);
        }

        private void SetNextMap(EMapDirection nextStartDir,float ratio = 1)
        {
            var dir = GetOppositeDir(nextStartDir);
            var nextForward = GetDirection(dir);
            Vector3 nextPosition = currentPosition + GetPositionOffsetByDirection(dir) * ratio;
            this.nextPosition = nextPosition;
            nextOffset = currentOffset + nextForward;
            //nextMapData = GetMap(nextPosition, nextStartDir,nextOffset);
        }

        public void GotoTransition()
        {
            SetNextMap(rpgCenterDir);
            float distance = float.MaxValue;
            Vector3 offset = GetDirection(GetOppositeDir(rpgCenterDir)) * 10f;
            Vector3 gotoPos = Vector3.zero;
            /*for (int i = 0; i < mapList[currentMapData.index].mapData.playerSpawnPoints.Count; i++)
            {
                var position = mapList[currentMapData.index].mapData.playerSpawnPoints[i];
                var d = Vector3.Distance(offset, position);
                if (d < distance)
                {
                    distance = d;
                    gotoPos = position;
                }
            }*/
            myGotoPosition = gotoPos;
            //LoadRpgMap();
        }

        /*public void RpgToRpg()
        {
            currentPosition = nextpo;
        }*/

        public void StartGoToRpg()
        {
            currentRpgRegion = pveData.rpgBattleRegions[0];
            rpgPosition = currentRpgRegion.battlePosition + currentPosition;
            //currentRegion
        }

        public void FindRandomRpgBattleRegion()
        {
            /*int offset = Random.Range(1, pveData.rpgBattleRegions.Count);
            int startId = 0;
            if (currentRpgRegion != null)
            {
                startId = currentRpgRegion.id;
            }
            int index = (startId + offset) % pveData.rpgBattleRegions.Count;
            currentRpgRegion = pveData.rpgBattleRegions[index];
            //rpgPosition = currentRpgRegion.battlePosition + currentPosition;
            rpgPosition = currentRegion.position + currentPosition;*/
            rpgPosition = GetRpgStageCenterPosition();
        }

        public void StartRpgTimeline(Vector3 position)
        {
            rpgPosition = position;
            rpgLight.SetActive(false);
        }

        public void RpgTimelineComplete()
        {
            rpgLight.SetActive(true);
        }
        public void RpgRestart()
        {
            currentPosition = rpgPosition;
            //LoadRpgMapSegment();
        }

        public void GotoRpg()
        {
            SetNextMap(GetOppositeDir(requiredOut));
        }

        private float tbsNextAngleOffset;

        public void GotoTbs(Vector3 currentPosition)
        {
            //SetNextMap(EMapDirection.left);
            float distance = float.MaxValue;
            EMapDirection dir = EMapDirection.right;
            /*var mapData = mapList[currentMapData.index];
            foreach (var item in mapData.directionInfo)
            {
                if (item.Value && item.Key != currentMapData.from)
                {
                    Vector3 position = this.currentPosition + GetPositionOffsetByDirection(item.Key);
                    float d = Vector3.Distance(currentPosition, position);
                    if (d < distance)
                    {
                        dir = item.Key;
                        distance = d;
                    }
                }
            }*/

            dir = GetOppositeDir(dir);
            if (dir == EMapDirection.left)
            {
                tbsNextAngleOffset = 0;
            }
            else if (dir == EMapDirection.right)
            {
                tbsNextAngleOffset = 180;
            }
            else if (dir == EMapDirection.top)
            {
                tbsNextAngleOffset = 90;
            }
            else if (dir == EMapDirection.bottom)
            {
                tbsNextAngleOffset = 270;
            }
            SetNextMap(dir);
        }

        public float GetTbsAngleOffset()
        {
            return tbsNextAngleOffset;
        }

        public Vector3 GetNextPosition()
        {
            return nextPosition;
        }

        public void GotoNormal()
        {
            var clearList = new List<int>();
            var fromOffset = currentOffset + GetDirection(currentMapData.from);
            foreach (var item in aroundMapData)
            {
                if (item.Value.offset == currentOffset || item.Value.offset == fromOffset)
                {
                    continue;
                }
                clearList.Add(item.Key);
            }

            for (int i = 0; i < clearList.Count; i++)
            {
                int id = clearList[i];
                GameObject.DestroyImmediate(aroundMapData[id].map);
                aroundMapData.Remove(id);
            }
            LoadAroundMap();
        }

        private void LoadRpgMap()
        {
            var nextDir = GetDirection(requiredOut);
            var offset = nextOffset + nextDir;
            var position = nextPosition + GetPositionOffsetByDirection(requiredOut);
            var map = CreateMapAndObjects(mapList[7]);
            map.transform.position = position;
            map.name = offset.ToString();
            var mapObj = new MapObj
            {
                map = map,
                from = GetOppositeDir(requiredOut),
                index = 7,
                offset = offset,
            };

            var index = GetIndexByOffset(offset);
            if (aroundMapData.TryGetValue(index,out var obj))
            {
                GameObject.DestroyImmediate(obj.map);
            }
            aroundMapData[index] = mapObj;
        }

        private Vector3 GetPositionOffsetByDirection(EMapDirection dir)
        {
            var forward = GetDirection(dir);
            return 50f * PveUtils.globalRatio * forward;
        }

        public Vector3 GetRpgEnemyBirthPosition(int stageId, int index)
        {
            return enemys[stageId][index - 1].position + rpgPosition; //levelData.stages[stageId].enemyBirthPositions[index] + rpgPosition + currentRegion.position;
        }

        public Vector3 GetRpgPlayerBirthPosition(int stageId, int index)
        {
            Vector3 position;
            if (!playerBirthPositions.TryGetValue(index, out position))
            {
                position = new Vector3(-2, 0, Random.Range(-0.5f,0.5f));
            }
            return rpgPosition + position;
        }

        public Vector3 GetObstacleSize(int stageId, int index)
        {
            return PveUtils.GetObstacleSize(levelData.stages[stageId].obstacles[index].obstacleId);
        }

        public int GetStageType(int stageId)
        {
            if (levelData.stages.Count > stageId)
            {
                return levelData.stages[stageId].stageType;
            }
            return 0;
        }


        public float GetStageParam(int stageId)
        {
            if (levelData.stages.Count > stageId)
            {
                return levelData.stages[stageId].stageParam;
            }

            return 0;
        }

        /*public Vector3 GetObstacleHidePosition(int stageId,int index)
        {
            return levelData.stages[stageId].obstacles[index].hidePoint + currentPosition;
            //return currentPosition + PveUtils.GetObstacleHidePosition(index);
        }*/

        public Vector3 GetObstaclePosition(int stageId,int index)
        {
            return levelData.stages[stageId].obstacles[index].position + rpgPosition;
            //return currentPosition + PveUtils.GetObstaclePosition(index);
        }
        public RpgLevelData.RpgObstacle GetObstacleInfo(int stageId, int index)
        {
            return obstacles[stageId][index].obstacleInfo;
        }

        public int GetRpgStageCount()
        {
            return levelData.stages.Count;
        }

        public List<Vector3> AttackPositions(int stageId)
        {
            List<Vector3> positions = new List<Vector3>();
            var attackPositions = levelData.stages[stageId].attackPositions;
            for (int i = 0; i < attackPositions.Count; i++)
            {
                positions.Add(attackPositions[i] + currentPosition);
            }
            return positions;
        }

        public void ClearStage()
        {
            for (int i = 0; i < stages.Count; i++)
            {
                stages[i].hasSpawned = false;
            }

            foreach (var item in enemys.Values)
            {
                for (int i = 0; i < item.Count; i++)
                {
                    item[i].hasSpawned = false;
                }
            }

            foreach (var item in obstacles.Values)
            {
                for (int i = 0; i < item.Count; i++)
                {
                    item[i].hasSpawned = false;
                }
            }
        }

        private PveMapRegion currentBattleRegion;
        public List<EnemySpawn> pveEnemySpawns = new List<EnemySpawn>();
        public List<ObstacleSpawn> pveObstacleSpawn = new List<ObstacleSpawn>();
        private Dictionary<int,PveMapRegion> regionBlackList = new Dictionary<int,PveMapRegion>();

        public void PveBattleFinished()
        {
            currentBattleRegion = null;
        }

        public void CheckIsLeaveBattleRegion(Vector3 position)
        {
            var region = currentBattleRegion;
            if (region == null)
            {
                return;
            }
            var center = region.battlePosition + currentPosition;
            var forward = Quaternion.AngleAxis(region.battleAreaRotation, Vector3.up) * Vector3.right;
            var rad = Vector3.Angle(center - position,forward) * Mathf.Deg2Rad;
            var distance = Vector3.Distance(center, position);
            var distToHeight = Mathf.Sin(rad) * distance;
            var distToWidth = Mathf.Cos(rad) * distance;
            var isLeave =  distToWidth > region.battleAreaWidth / 2 ||
                   distToHeight > region.battleAreaHeight / 2;
        }

        public bool CheckBattleStart(Vector3 position)
        {
            /*if (currentBattleRegion != null)
            {
                return false;
            }*/
            for (int i = 0; i < pveData.regions.Count; i++)
            {
                var region = pveData.regions[i];
                if (regionBlackList.ContainsKey(region.id))
                {
                    continue;
                }
                var center = region.battlePosition + currentPosition;
                var forward = Quaternion.AngleAxis(region.battleAreaRotation, Vector3.up) * Vector3.right;
                var rad = Vector3.Angle(center - position,forward) * Mathf.Deg2Rad;
                var distance = Vector3.Distance(center, position);
                var distToHeight = Mathf.Sin(rad) * distance;
                var distToWidth = Mathf.Cos(rad) * distance;
                if (distToWidth <= region.battleAreaWidth / 2 &&
                    distToHeight <= region.battleAreaHeight / 2 || true)
                {
                    currentBattleRegion = pveData.regions[i];
                    regionBlackList.Add(region.id,region);
                    //pveEnemySpawns.Clear();
                    //pveObstacleSpawn.Clear();
                    if (pveData.regions[i].battles.Count > 0)
                    {
                        var battle = pveData.regions[i].battles[0];
                        for (int j = 0; j < battle.enemyIds.Count; j++)
                        {
                            pveEnemySpawns.Add(new EnemySpawn
                            {
                                hasSpawned = false,
                                id = battle.enemyIds[j],
                                param = battle.enemySpawnParam[j],
                                position = battle.enemyBirthPositions[j] + currentPosition,
                                stageId = i,
                                hatredDistance = battle.enemyHatredDistances[j],
                                type = battle.enemySpawnType[j],
                            });
                        }

                        for (int j = 0; j < battle.obstacles.Count; j++)
                        {
                            var obstacle = battle.obstacles[j];
                            pveObstacleSpawn.Add(new ObstacleSpawn
                            {
                                hasSpawned = false,
                                obstacleInfo = obstacle,
                            });
                        }
                    }
                    //return true;
                }
            }
            return false;
        }

        /// <summary>
        ///打开窗口的时候，关闭场景雾效果
        /// </summary>
        /// <param name="enable"></param>
        public void EnableFogEffect(bool enable)
        {
            if (enable)
            {
                ApplyFog();
            }
            else
            {
                RenderSettings.fog = false;
            }
           
        }
        public void Dispose()
        {
            levelData = null;
            GameObject.DestroyImmediate(root);
            if (skyBox != null)
            {
                GameObject.DestroyImmediate(skyBox.gameObject);
                skyBox = null;
            }
            
            if (refrectionProbe != null)
            {
                GameObject.DestroyImmediate(refrectionProbe);
                refrectionProbe = null;
            }
            
            RenderSettings.fog = originFog;
            RenderSettings.fogColor = originFogColor;
            RenderSettings.fogMode = originFogMode;
            RenderSettings.fogStartDistance = originFogStart;
            RenderSettings.fogEndDistance = originFogEnd;
            LightmapSettings.lightmaps = originLightMap;
            hangMusic = null;
        }
    }
}
